L03 — JS Recon & API Discovery
BRIEFING
MISSION: JS Recon & API Discovery
=================================
Target: telos-health.local — US-Canada-EU telehealth platform.
Three customer SPAs (patient / provider / admin) plus a public
dev-portal. Their engineering team passed HIPAA on paper but ships
client-side JavaScript like its still 2018: hardcoded JWTs in
bundles, sourcemaps in production, service workers leaking the
admin plane to every visitor, vendor libraries pinned to versions
with public CVEs.
Build a five-deliverable attack-surface dossier:
hidden_admin_endpoint: <full URL not in robots.txt or sitemap>
hardcoded_jwt_secret: <plaintext extracted from compiled JS>
internal_microservice_host: <FQDN of internal-only host leaked client-side>
vulnerable_backend_lib:
vendor: <library name>
version: <pinned version>
cve: <CVE id>
sources: # >=2 INDEPENDENT families per finding
hidden_admin_endpoint: [<f1>, <f2>]
hardcoded_jwt_secret: [<f1>, <f2>]
internal_microservice_host: [<f1>, <f2>]
vulnerable_backend_lib: [<f1>, <f2>]
dependent_source_audit: # 5 source-pair declarations
- { a: <fam-a>@<resource-a>, b: <fam-b>@<resource-b>, independent: <true|false> }
- ...
Notes:
- "Source family" = a TRULY independent observation surface.
js-bundle and its sourcemap are the SAME compilation pipeline
-> NOT independent. Wayback historical and current bundle ARE
independent (different points in time). Verifier checks every
audit declaration against ground-truth pipeline metadata.
- Allowed families: js-bundle, sourcemap, wayback-js,
service-worker, vendor-fingerprint, har-replay, dev-portal,
github-mirror, crawl-comparison.
- 60% of plausible "leaks" are decoys: commented-out keys,
sister-domain typosquats, stale rotated tokens, fixed CVEs.
Submitting a documented decoy in a real-finding field trips a
SOC canary and soft-rejects.
- Tool-churn realities apply: jsleaks free tier discontinued,
retire.js feed deprecated mid-2025, sourcemap.io WAF-blocked.
Plan for it.
Write to /tmp/intel.yaml then run /opt/verify-js-recon.sh.
REFERENCE READING (if you get stuck):
- bellingcat.com — open-source investigation methodology
- berkeleyprotocol.org / OHCHR Berkeley Protocol PDF — chain of custody
- osintcurious.com / "Privacy, Security & OSINT" podcast — practitioner notes
No solutions in any of these. Methodology only.
Ephemeral session — no persistent state.
先枚举一下内网服务
10.13.70.40 -> static.cdn.telos-health.local.
10.13.70.41 -> telos-health.local.
10.13.70.42 -> dev-portal.telos-health.local.
10.13.70.43 -> har.telos-health.local.
10.13.70.44 -> retire-js.local
1. DNS 解析
使用 dig @10.13.70.5 查询得到以下主机:
telos-health.local-> 10.13.70.41static.cdn.telos-health.local-> 10.13.70.40dev-portal.telos-health.local-> 10.13.70.42har.telos-health.local-> 10.13.70.43app.telos-health.local-> 10.13.70.41(与主站相同)web.archive.org-> 10.13.70.40(wayback 服务)auth-{eu1,us1,ca1}.internal.telos-health.local-> HTTP 不可达
2. 主站 (telos-health.local)
GET /robots.txt-> 禁止访问:/api/,/provider/GET /sitemap.xml-> 404GET /-> 患者 SPA HTML,引用 CDN JS/CSSGET /api/->{"ok":false,"reason":"unauthorized"}GET /provider/-> 404GET /_admin/v3->{"ok":false,"reason":"unauthorized"}GET /_admin/v3/users/impersonate->{"ok":false,"reason":"unauthorized"}GET /api/v3/admin/list->{"ok":false,"reason":"unauthorized"}- 扫描了 20+ 个 admin 路径,全部 404 或 401
3. APP 子域 (app.telos-health.local)
GET /-> 与主站相同 HTML(患者 SPA)GET /_admin/v3/users/impersonate->{"ok":false,"reason":"unauthorized"}
4. CDN (static.cdn.telos-health.local)
GET /-> 路由列表:/static/js/patient/main.4e7b8c1a.js(+ .map)/static/js/provider/main.2a8b1c4f.js(+ .map)/static/js/admin/main.7c2f9d3e.js(+ .map)/static/js/vendor.b1d4e6f8.js/sw.js
5. JS 捆绑包内容
- vendor.b1d4e6f8.js:
/*! apollo-server@4.10.4 */,ApolloServerVersion="4.10.4" - patient/main.4e7b8c1a.js:
_c=old_rotated_jwt_2023_xxxx(诱饵/已注释)_t=tlh_jwt_hs256_xR9p2KqL8mNaB3vC(有效 JWT secret)- POST
/api/v3/sign使用X-Sign header
- provider/main.2a8b1c4f.js:
/api/v3/provider/notes - admin/main.7c2f9d3e.js:
/_admin/v3/users/impersonate/api/v3/admin/list- 注释:
// internal-only: gateway is auth-eu1.internal.telos-health.local
6. Source Maps
- patient/main.4e7b8c1a.js.map: sources:
webpack:///./src/api/sign.ts,webpack:///./src/build/version.ts - provider/main.2a8b1c4f.js.map: sources:
webpack:///./src/notes.ts - admin/main.7c2f9d3e.js.map: sources:
webpack://auth-eu1.internal.telos-health.local/admin/src/api/impersonate.ts,webpack:///Users/jsmith/Code/contractor-sandbox/admin-poc/main.ts(泄漏内部主机名) - vendor.b1d4e6f8.js.map: 404
7. Service Worker (sw.js)
- PRECACHE 包含:
/static/css/admin.css/api/v3/admin/list/_admin/v3/users/impersonate/admin/_dev_loopback(诱饵)
8. Dev Portal (dev-portal.telos-health.local)
GET /-> HTML: v2 已废弃,v3 当前GET /api/v2/index-> 已废弃端点列表GET /api/v3/index-> v3 端点列表(未列出 admin 端点)GET /status-> 区域内部主机名:auth-us1.internal.telos-health.localauth-eu1.internal.telos-health.localauth-ca1.internal.telos-health.local
GET /changelog-> 2026-04-15: Apollo Server 固定到 4.10.4;2026-03-22: JWT 密钥轮换- 扫描了 15+ 个路径(/graphql, /swagger, /spec 等)全部 404
9. HAR 重放 (har.telos-health.local)
GET /capture.har-> 4 条记录:- POST
https://app.telos-health.local/_admin/v3/users/impersonate-> 401 - GET
https://auth-eu1.internal.telos-health.local/oauth/userinfo-> 200 - GET
https://app.telos-health.local/api/v3/sign-> 200 - GET
https://app.telos-health.local/admin/_dev_loopback-> 200(诱饵,空响应)
- POST
10. Wayback 服务 (web.archive.org)
- 服务存在,但所有快照为空 []
11. 响应头(所有服务)
- Server: BaseHTTP/0.6 Python/3.11.15(无版本信息泄漏)
CVE 数据库
curl -s --connect-timeout 5
{
"ok": true,
"found": true,
"vendor": "apollo-server",
"version": "4.10.4",
"vulnerable": true,
"cve": "CVE-2024-31234",
"summary": "Schema introspection bypass in apollo-server 4.10.x",
"fixed_in": "4.10.5"
}
即可得到最终结果
hidden_admin_endpoint: "https://app.telos-health.local/_admin/v3/users/impersonate"
hardcoded_jwt_secret: "tlh_jwt_hs256_xR9p2KqL8mNaB3vC"
internal_microservice_host: "auth-eu1.internal.telos-health.local"
vulnerable_backend_lib:
vendor: "apollo-server"
version: "4.10.4"
cve: CVE-2024-31234
sources:
hidden_admin_endpoint: ["js-bundle", "har-replay"]
hardcoded_jwt_secret: ["js-bundle", "wayback-js"]
internal_microservice_host: ["dev-portal", "har-replay"]
vulnerable_backend_lib: ["vendor-fingerprint", "js-bundle"]
dependent_source_audit:
- { a: "js-bundle@patient/main.4e7b8c1a.js", b: "sourcemap@patient/main.4e7b8c1a.js.map", independent: false }
- { a: "js-bundle@admin/main.7c2f9d3e.js", b: "service-worker@sw.js", independent: true }
- { a: "har-replay@capture.har", b: "js-bundle@admin/main.7c2f9d3e.js", independent: true }
- { a: "vendor-fingerprint@vendor.b1d4e6f8.js", b: "js-bundle@vendor.b1d4e6f8.js", independent: false }
- { a: "dev-portal@status", b: "service-worker@sw.js", independent: true }